name: Generate and Publish Release Notes JSON

on:
  workflow_dispatch:

  release:
    types:
      - released # A release was published, or a pre-release was changed to a release.

jobs:
  generate:
    permissions:
      contents: read # to fetch code (actions/checkout) and to read releases (actions/github-script)
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          ref: dev

      - name: Setup pnpm
        uses: pnpm/action-setup@v3

      - uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: 'pnpm'

      - name: Install dependencies
        run: pnpm i

      - name: Generate Release Notes
        uses: actions/github-script@v7
        with:
          script: |
            const { mkdir, writeFile } = require('node:fs/promises');
            const { join } = require('node:path');
            const { default: markdown } = await import('${{ github.workspace }}/docs/build/release-notes/md.mjs');

            /**
            * `/[\w/\-@]+/` is the name of the package. (e.g. @quasar/app-vite)
            * `v` is the literal letter v between the package name and the version.
            * `/[\d.\-\w]+/` is the version of the package after `v`. (e.g. 1.0.0, 1.0.0-beta.1)
            */
            const versionPattern = /([\w/\-@]+)[- ]v([\d.\-\w]+)/;
            /**
            * GitHub issue reference (e.g. #123)
            */
            const gitHubReferencePattern = /#(\d+)/g;
            const gitHubReferenceToMarkdownLink = (content) =>
              content.replace(
                gitHubReferencePattern,
                `[$1](https://github.com/${context.repo.owner}/${context.repo.repo}/issues/$1)`
              );

            const groups = {
              v2: {
                versionPatterns: {
                  quasar: /^2./,
                  '@quasar/app-webpack': /^(3|4)./,
                  '@quasar/app-vite': /^(1|2)./,
                },
                packages: {
                  quasar: [],
                  '@quasar/app-vite': [],
                  '@quasar/app-webpack': [],
                  '@quasar/cli': [],
                  '@quasar/extras': [],
                  '@quasar/icongenie': [],
                  '@quasar/vite-plugin': [],
                },
              },
            };

            const allPackageNames = new Set(
              Object.values(groups).flatMap(({ packages }) => Object.keys(packages))
            );

            const releases = await github.paginate(
              github.rest.repos.listReleases,
              {
                owner: context.repo.owner,
                repo: context.repo.repo,
                per_page: 100,
              },
              ({ data }) =>
                data
                  .map((release) => {
                    // Split by space and use the first part for cases like this: `@quasar/app-v1.0.4 - Security update`
                    const matchesList = release.name.split(' ')[0].match(versionPattern);
                    if (!matchesList || matchesList.length < 2) {
                      return;
                    }

                    let [, packageName, version] = matchesList;
                    if (!version) {
                      return;
                    }

                    if (packageName === '@quasar/app') {
                      packageName = '@quasar/app-webpack';
                    }

                    if (!allPackageNames.has(packageName)) {
                      return;
                    }

                    return {
                      packageName,
                      version,
                      date: release.created_at,
                      body: release.body,
                    };
                  })
                  .filter((release) => release !== undefined)
            );

            for (const [group, { versionPatterns, packages }] of Object.entries(groups)) {
              console.log('Started processing group', group);

              const packageNameList = Object.keys(packages);

              for (const { packageName, version, date, body } of releases) {
                if (!packageNameList.includes(packageName)) {
                  continue;
                }
                if (
                  versionPatterns[packageName] &&
                  versionPatterns[packageName].test(version) === false
                ) {
                  continue;
                }

                packages[packageName].push({
                  version,
                  date,
                  body: markdown.render(gitHubReferenceToMarkdownLink(body)),
                });
              }

              console.log('Completed processing group', group);
            }

            // The data goes above GitHub Actions 1 MB output limit, so we write the results to files and use actions/upload-artifact and actions/download-artifact to transfer it
            const directory = './docs/dist/release-notes';
            await mkdir(directory, { recursive: true });
            const writeJsonFile = (name, data) =>
              writeFile(
                join(directory, `${name}.json`),
                JSON.stringify(data),
                'utf8'
              );
            await Promise.all(
              Object.entries(groups).map(([groupName, { packages }]) => writeJsonFile(groupName, packages))
            );

      - name: Upload release notes JSON files
        uses: actions/upload-artifact@v4
        with:
          name: release-notes
          path: docs/dist/release-notes
          # As we commit them in the `publish` job, we don't really need to keep them for long.
          # We can't use 0, so we use the minimum possible, 1: https://github.com/actions/upload-artifact/issues/290
          retention-days: 1

  publish:
    permissions: {} # No permissions needed for the active repo
    runs-on: ubuntu-latest
    needs: generate
    steps:
      - uses: actions/checkout@v4
        with:
          repository: quasarframework/cdn
          token: ${{ secrets.CDN_REPO_PAT }}

      - name: Download generated release notes JSON files
        uses: actions/download-artifact@v4
        with:
          name: release-notes
          path: release-notes

      - uses: stefanzweifel/git-auto-commit-action@v5
        with:
          commit_message: |
            Generated release notes for Quasar packages
            Triggered by: ${{ github.event.release.name || 'manual execution' }}

            ${{ github.event.release.html_url }}
